﻿/* 
 * Copyright 2010 Justin Pealing
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 *     
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */

using System;
using System.Globalization;
using System.Reflection;
using System.Web;
using System.Web.Hosting;
using Minnow.Web.Http;

namespace Minnow.Web.Asp
{
    /// <summary>
    /// Marshals Asp.Net requests into the Asp.Net app domain
    /// </summary>
    public class AspNetMarshaller : MarshalByRefObject, IRegisteredObject
    {
        /// <summary>
        /// Executes an Asp.Net request
        /// </summary>
        /// <param name="page">Name of the page</param>
        /// <param name="query">Query</param>
        /// <returns>Response string</returns>
        public void Process(string FilePath, IHttpRequest Request, IHttpResponse Response)
        {
            WebWorkerRequest request = new WebWorkerRequest(Request, Response, FilePath);
            HttpRuntime.ProcessRequest(request);
        }

        /// <summary>
        /// Creates an Asp.Net app domain.
        /// </summary>
        /// <param name="HostType">Host object to instantiate in the worker app domain.</param>
        /// <param name="VirtualDir">Virtual directory path.</param>
        /// <param name="PhysicalDir">Full path to the physical directory.</param>
        /// <returns></returns>
        /// <remarks>This method creates the worker app domain in a way that the host doesn't need to be
        /// in the GAC or bin directory of the application.</remarks>
        public static object CreateApplicationHost(Type HostType, string VirtualDir, string PhysicalDir)
        {
            string uniqueAppString = string.Concat(VirtualDir, PhysicalDir).ToLowerInvariant();
            string appId = (uniqueAppString.GetHashCode()).ToString("x", CultureInfo.InvariantCulture);

            ApplicationManager appManager = ApplicationManager.GetApplicationManager();
            Type buildManagerHostType = typeof(HttpRuntime).Assembly.GetType("System.Web.Compilation.BuildManagerHost");
            IRegisteredObject buildManagerHost = appManager.CreateObject(appId, buildManagerHostType, VirtualDir, PhysicalDir, false);

            buildManagerHostType.InvokeMember(
                "RegisterAssembly",
                BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic,
                null,
                buildManagerHost,
                new object[2] { HostType.Assembly.FullName, HostType.Assembly.Location });

            // create Host in the worker app domain
            return appManager.CreateObject(appId, HostType, VirtualDir, PhysicalDir, false);
        }

        #region IRegisteredObject Members

        public void Stop(bool immediate)
        {
            // TODO: this
            HostingEnvironment.UnregisterObject(this);
        }

        #endregion
    }
}
